<script setup>
import {
  CheckOutlined,
  PlusOutlined,
  MinusOutlined,
  SearchOutlined,
  ClearOutlined,
  EditOutlined,
  LoadingOutlined
} from '@ant-design/icons-vue';
import {message}   from "ant-design-vue";
import axios  from "axios";

const formRef = ref();
const formModalRef = ref();
const searchForm = reactive({
  username: '',
});

//所有条件搜索
const onFinish = values => {
  getUserList(values);
};
//清除条件搜索
const resetForm = () => {
  formRef.value.resetFields();
}
const open = ref(false);
const RefUsername = ref(null);
const showModal = (id) => {
  open.value = true;
  nextTick(() => {
    RefUsername.value.focus();
  });
  if (id) {
    axios.get( '/api/user-info' + '?id=' + id).then(res => {
      if (res.data.code !== 200) {
        message.error(res.data.msg);
        return false;
      } else {
        formData.value = res.data.data;
      }
    }).catch(err => {
      console.log(err);
      message.error('请求失败');
    });
  }
};
// TODO: 提交表单
const handleOk = () => {
  let requestUrl = (formData.value.id) ? '/api/user-edit' : '/api/user-create';
  axios.post(requestUrl, formData.value).then(res => {
    if (res.data.code !== 200) {
      message.error(res.data.msg);
    } else {
      message.success(res.data.msg, 2, () => {
        open.value = false;
        getUserList(searchForm);
      });
    }
  }).catch(err => {
    console.log(err);
    message.error('请求失败');
  });
};
// todo 关闭模态框
const handleCancel = () => {
  open.value = false;
  formModalRef.value.resetFields();
};
//表单数据
const formData = ref({
  id: 0,
  avatar: '',
  username: '',
  password: '',
  nickname: '',
  state: 1,
  sex: 1,
  age: 18,
  area: [],
  address: '',
  tags: [],
  remark: '',
  phone: '',
});
//表单验证规则
const rules = {
  username: [
    {
      required: true,
      trigger: ['blur', 'change'],
      validator: async (_rule, value) => {
        if (value === '') {
          return Promise.reject('用户名不能为空');
        } else if (!/^1[3456789]\d{9}$/.test(value)) {
          return Promise.reject('手机号格式不正确');
        }
      },
    }
  ],
  password: [
    {
      required: true,
      trigger: ['blur', 'change'],
      validator: async (_rule, value) => {
        if (value === '') {
          return Promise.reject('密码不能为空');
        } else if (value.length < 8 || value.length > 16) {
          return Promise.reject('密码长度为8-16位');
        } else if (!/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$/.test(value)) {
          return Promise.reject('密码由大小写字母和数字组成');
        }
      },
    }
  ],
  nickname: [
    {
      required: true,
      trigger: ['blur', 'change'],
      validator: async (_rule, value) => {
        if (value === '') {
          return Promise.reject('昵称不能为空');
        } else if (!/^[\u4e00-\u9fa5a-zA-Z0-9_]+$/.test(value)) {
          return Promise.reject('昵称由大小写字母、数字、下划线组成');
        } else if (value.length > 16) {
          return Promise.reject('昵称长度为1-16位');
        }
      },
    }
  ],
  tags: [
    {
      required: true,
      type: 'array',
      message: '请选择标签',
      trigger: ['blur', 'change'],
    }
  ],
  area: [
    {
      required: true,
      message: '请选择地区',
      trigger: ['blur', 'change'],
    }
  ],
  address: [
    {
      required: true,
      message: '请输入地址',
      trigger: ['blur', 'change'],
    }
  ]
};
//表格的表头
const columns = [
  {
    title: '用户名',
    dataIndex: 'username',
    key: 'username',
    align: 'center',
  },
  {
    title: '昵称',
    dataIndex: 'nickname',
    key: 'nickname',
    align: 'center',
  },
  {
    title: '头像',
    key: 'avatar',
    dataIndex: 'avatar',
    align: 'center',
  },
  {
    title: '年龄',
    dataIndex: 'age',
    key: 'age',
    align: 'center',
  },
  {
    title: '地址',
    dataIndex: 'address',
    key: 'address',
    align: 'center',
  },
  {
    title: '标签',
    key: 'tags',
    dataIndex: 'tags',
  },
  {
    title: '状态',
    key: 'state',
    dataIndex: 'state',
  },
  {
    title: '性别',
    key: 'sex',
    dataIndex: 'sex',
  },
  {
    title: '备注',
    key: 'remark',
    dataIndex: 'remark',
  },
  {
    title: '日期',
    key: 'create_time',
    dataIndex: 'create_time',
  },
  {
    title: '操作',
    key: 'action',
  },
];
//表格的默认数据
const data = ref([]);
//分页器
const pagination = reactive({
  pageSize: 10,
  total: 0,
  current: 1,
  showSizeChanger: true,
  showTotal: function (total) {
    return `共${total}条`;
  },
  onShowSizeChange: (current, pageSize) => {
    pagination.current = current;
    pagination.pageSize = pageSize;
    getUserList(searchForm);
  },
  onChange: (page) => {
    pagination.current = page;
    getUserList(searchForm);
  },
});
// 获取用户列表
const getUserList = (values) => {
  let params = {
    page: pagination.current,
    pageSize: pagination.pageSize,
    ...values
  };
  axios.get('/api/user-list', {
    params: params
  }).then(res => {
    if (res.data.code !== 200) {
      message.error(res.data.msg);
      return;
    }
    data.value = res.data.data.list;
    pagination.total = res.data.data.total;
    pagination.current = parseInt(res.data.data.page);
    pagination.pageSize = parseInt(res.data.data.pageSize);
  }).catch(err => {
    console.log(err);
    message.error('请求失败');
  });
}
//获取地区列表
const areaOptions = ref([]);
const getAreaList = () => {
  axios.get( '/api/area-list').then(res => {
    if (res.data.code !== 200) {
      message.error(res.data.msg);
      return;
    }
    areaOptions.value = res.data.data;
  }).catch(err => {
    console.log(err);
    message.error('请求失败');
  });
}
//获取标签列表
const tagOptions = ref([]);
const getTagsList = () => {
  axios.get( '/api/tags-all').then(res => {
    if (res.data.code === 200) {
      tagOptions.value = res.data.data;
    } else {
      message.error(res.data.msg);
    }
  }).catch(err => {
    console.log(err);
    message.error('请求失败');
  });
}
const stateOptions = [
  {label: '正常', value: 1},
  {label: '风控', value: 0},
  {label: '限制', value: 2},
];
// 选择择状态
const handleStateChange = (id, $event) => {
  axios.post('/api/user-edit', {
    id: id,
    state: $event
  }).then(res => {
    if (res.data.code !== 200) {
      message.error(res.data.msg);
    } else {
      message.success(res.data.msg);
    }
  }).catch(err => {
    console.log(err);
    message.error('请求失败');
  });
}
// 修改性别
const handleSexChange = (id, $event) => {
  const value = $event ? 1 : 0;
  axios.post( '/api/user-edit', {id: id, sex: value}).then(res => {
    if (res.data.code !== 200) {
      message.error(res.data.msg);
    } else {
      message.success(res.data.msg);
    }
  }).catch(err => {
    console.log(err);
    message.error('请求失败');
  });
}
//删除用户
const handleDelete = (id) => {
  axios.post('/api/user-delete', {id: id}).then(res => {
    if (res.data.code !== 200) {
      message.error(res.data.msg);
    } else {
      message.success(res.data.msg, 2, () => {
        data.value = data.value.filter(item => item.id !== id);
      });
    }
  }).catch(err => {
    console.log(err);
    message.error('请求失败');
  });
}
//点击修改按钮
const editableData = reactive({});
const save = (id) => {
  let remark = editableData[id].remark;
  axios.post('/api/user-edit', {id: id, remark: remark}).then(res => {
    if (res.data.code !== 200) {
      message.error(res.data.msg);
    } else {
      message.success(res.data.msg, 1, () => {
        data.value.forEach(item => {
          if (item.id === id) {
            item.remark = remark;
          }
        });
        delete editableData[id];
      });
    }
  }).catch(err => {
    console.log(err);
    message.error('请求失败');
  });
}
const edit = (id) => {
  editableData[id] = data.value.find(item => item.id === id);
}
//上传头像
const loading = ref(false);
const fileList = ref([]);
const handleChange = info => {
  if (info.file.status === 'uploading') {
    loading.value = true;
    return;
  }
  if (info.file.status === 'done' && info.file.response) {
    formData.value.avatar = info.file.response.data.url;
    loading.value = false;
  }
  if (info.file.status === 'error') {
    loading.value = false;
    message.error('upload error');
  }
};
const beforeUpload = file => {
  const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  if (!isJpgOrPng) {
    message.error('You can only upload JPG file!');
  }
  const isLt2M = file.size / 1024 / 1024 < 2;
  if (!isLt2M) {
    message.error('Image must smaller than 2MB!');
  }
  return isJpgOrPng && isLt2M;
};
const uploadUrl = '/api/upload';

// 页面加载时调用
onMounted(() => {
  getUserList();
  getAreaList();
  getTagsList();
});
</script>

<template>
  <a-space :size="16" style="margin-bottom: 16px;">
    <a-form layout="inline" ref="formRef" name="user_search" :model="searchForm" @finish="onFinish">
      <a-form-item label="用户名" name="username">
        <a-input v-model:value="searchForm.username" placeholder="请输入用户名" allow-clear></a-input>
      </a-form-item>
      <a-row>
        <a-space>
          <a-button type="primary" html-type="submit"><SearchOutlined />搜索</a-button>
          <a-button @click="resetForm"><ClearOutlined />重置</a-button>
        </a-space>
      </a-row>
    </a-form>
    <a-button type="primary" @click="showModal(0)"><PlusOutlined />添加数据</a-button>
  </a-space>


  <a-modal v-model:open="open" title="添加用户" @ok="handleOk" @cancel="handleCancel" ok-text="确定" cancel-text="取消">
    <a-form name="addModal" ref="formModalRef" :model="formData" :rules="rules" :label-col="{span: 4,}" :wrapper-col="{span: 20,}">
      <a-form-item label="用户名" name="username">
        <a-input v-model:value="formData.username" placeholder="请填写用户名" autocomplete="off" ref="RefUsername" />
      </a-form-item>
      <a-form-item label="密码" name="password">
        <a-input-password v-model:value="formData.password" placeholder="请输入密码" autocomplete="off" />
      </a-form-item>
      <a-form-item label="昵称" name="nickname">
        <a-input v-model:value="formData.nickname" placeholder="请输入昵称" autocomplete="off" />
      </a-form-item>
      <a-form-item label="手机号" name="phone">
        <a-input-group compact>
          <a-input v-model:value="formData.phone" placeholder="请输入手机号" autocomplete="off" style="width: calc(100% - 100px)" />
          <a-button>查询手机</a-button>
        </a-input-group>
      </a-form-item>
      <a-form-item label="头像" name="avatar">
        <a-upload
            v-model:file-list="fileList"
            name="avatar"
            list-type="picture-card"
            class="avatar-uploader"
            :show-upload-list="false"
            :action="uploadUrl"
            :before-upload="beforeUpload"
            :max-count="1"
            @change="handleChange"
        >
          <img v-if="formData.avatar" :src="formData.avatar" alt="avatar" width="100" height="100" />
          <div v-else>
            <loading-outlined v-if="loading"></loading-outlined>
            <plus-outlined v-else></plus-outlined>
            <div class="ant-upload-text">Upload</div>
          </div>
        </a-upload>
      </a-form-item>
      <a-form-item label="性别" name="sex">
        <a-switch v-model:checked="formData.sex" checked-children="男" un-checked-children="女" v-remove-aria-hidden />
      </a-form-item>
      <a-form-item label="邮箱" name="email">
        <a-input v-model:value="formData.email" placeholder="请输入邮箱" autocomplete="off" />
      </a-form-item>
      <a-form-item label="年龄" name="age" style="margin: 5px" required>
        <a-input-number v-model:value="formData.age" :min="18" :max="60" addon-after="岁">
          <template #upIcon><PlusOutlined /></template>
          <template #downIcon><MinusOutlined /></template>
        </a-input-number>
      </a-form-item>
      <a-form-item label="地址" name="area" required>
        <a-cascader v-model:value="formData.area" :options="areaOptions" placeholder="请选择地址" v-remove-aria-hidden />
      </a-form-item>
      <a-form-item label="详细地址" name="address" required>
        <a-input v-model:value="formData.address" placeholder="请输入地址" />
      </a-form-item>
      <a-form-item label="标签" name="tags" required>
        <a-checkbox-group v-model:value="formData.tags" :options="tagOptions" v-remove-aria-hidden></a-checkbox-group>
      </a-form-item>
      <a-form-item label="状态" name="state" required>
        <a-radio-group v-model:value="formData.state" :options="stateOptions" option-type="button"></a-radio-group>
      </a-form-item>
      <a-form-item label="备注" name="remark" required>
        <a-textarea v-model:value="formData.remark" :rows="4" placeholder="请输入备注" />
      </a-form-item>
    </a-form>
  </a-modal>
  
  <!-- 表格渲染 -->
  <div style="margin: 10px 0">
    <a-table class="ant-table-striped" bordered
             :columns="columns"
             :data-source="data"
             :pagination="pagination"
             :row-class-name="(_record, index) => (index % 2 === 1 ? 'table-striped' : null)"
             @change="getUserList"
    >
      <template #headerCell="{ column }">
        <template v-if="column.key === 'username'">
          <span>{{ column.title }}</span>
        </template>
      </template>

      <template #bodyCell="{ column, text, record }">
        <template v-if="column.key === 'username'">
          <a>{{ record.username }}</a>
        </template>
        <template v-else-if="column.key === 'avatar'">
          <a-avatar v-if="record.avatar" :src="record.avatar"></a-avatar>
          <a-avatar v-else :style="{backgroundColor: '#87d068'}">
            {{ record.nickname.substring(0, 1) }}
          </a-avatar>
        </template>
        <template v-else-if="column.key === 'tags'">
        <span>
          <a-tag v-for="(item, index) in record.tags" :key="index">{{ item }}</a-tag>
        </span>
        </template>
        <template v-else-if="column.key === 'state'">
          <a-select v-model:value="record.state" :options="stateOptions" style="width: 80px" @change="handleStateChange(record.id, $event)" />
        </template>
        <template v-else-if="column.key === 'age'">
          <span>{{ record.age }} 岁</span>
        </template>
        <template v-else-if="column.key === 'address'">
          <span>{{ record.address }}</span>
        </template>
        <template v-else-if="column.key === 'sex'">
          <a-switch v-model:checked="record.sex" checked-children="男" un-checked-children="女"
                    @change="handleSexChange(record.id, $event)" />
        </template>
        <template v-else-if="column.key === 'remark'">
          <div class="editable-cell">
            <div v-if="editableData[record.id]" class="editable-cell-input-wrapper">
              <a-input v-model:value="editableData[record.id].remark" @pressEnter="save(record.id)" />
              <check-outlined class="editable-cell-icon-check" @click="save(record.id)" />
            </div>
            <div v-else class="editable-cell-text-wrapper">
              {{ text || ' ' }}
              <edit-outlined class="editable-cell-icon" @click="edit(record.id)" />
            </div>
          </div>
        </template>

        <template v-else-if="column.key === 'action'">
          <a-space size="small">
            <a-button type="primary">
              <router-link :to="{ path: '/user/info', query: {id: record.id}}">查看详情</router-link>
            </a-button>
            <a-button @click="showModal(record.id)">编辑</a-button>
            <a-popconfirm title="确定删除吗?" @confirm="handleDelete(record.id)" ok-text="确认" cancel-text="取消">
              <a-button type="primary" danger>删除</a-button>
            </a-popconfirm>
          </a-space>
        </template>
      </template>
    </a-table>
    <router-view></router-view>
  </div>
</template>

<style lang="less" scoped>
.ant-input-number :deep(.ant-input-number-handler-wrap) {
  opacity: 1 !important;
}

[data-doc-theme='light'] .ant-table-striped :deep(.table-striped) td {
  background-color: #fafafa;
}

[data-doc-theme='dark'] .ant-table-striped :deep(.table-striped) td {
  background-color: rgb(29, 29, 29);
}

.editable-cell {
  position: relative;
  
  .editable-cell-input-wrapper,
  .editable-cell-text-wrapper {
    padding-right: 24px;
  }
  
  .editable-cell-text-wrapper {
    padding: 5px 24px 5px 5px;
  }
  
  .editable-cell-icon,
  .editable-cell-icon-check {
    position: absolute;
    right: 0;
    width: 20px;
    cursor: pointer;
  }
  
  .editable-cell-icon {
    margin-top: 4px;
    display: none;
  }
  
  .editable-cell-icon-check {
    line-height: 28px;
  }
  
  .editable-cell-icon:hover,
  .editable-cell-icon-check:hover {
    color: #108ee9;
  }
  
  .editable-add-btn {
    margin-bottom: 8px;
  }
}

.editable-cell:hover .editable-cell-icon {
  display: inline-block;
}

.avatar-uploader > .ant-upload {
  width: 128px;
  height: 128px;
}

.ant-upload-select-picture-card i {
  font-size: 32px;
  color: #999;
}

.ant-upload-select-picture-card .ant-upload-text {
  margin-top: 8px;
  color: #666;
}
</style>